//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2013 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef _BUOLA_UTILITY_UTRACKABLE_H_
#define _BUOLA_UTILITY_UTRACKABLE_H_

#include <buola/buola.h>

namespace buola {

///\addtogroup utility
///@{

/////////////////////////////////////////////////////////////////////////////////////////////////
///
/// tracks deletion of an object
///
/// A pointer to an object of this class is returned by UTrackable::GetDeleteTracker(). This
/// object can then be used to check whether the particular trackable object has been deleted.
///
/////////////////////////////////////////////////////////////////////////////////////////////////
class UDeleteTracker : public UShared
{
    ///default constructor (can only be accessed from UTrackable)
    UDeleteTracker()
        :   mDeleted(false)
    {}

public:
    ///returns \c true if the tracked object has been deleted
    bool Deleted()  {   return mDeleted;    }
    
private:
    bool mDeleted;

    friend class UTrackable;
};

///intrusive pointer to \ref UDeleteTracker
///
///This is the type returned by UTrackable::GetDeleteTracker(), and it is the only way that
///\ref UDeleteTracker should be used.
typedef intrusive_ptr<UDeleteTracker> PDeleteTracker;

/////////////////////////////////////////////////////////////////////////////////////////////////
///
/// makes deletion of the object trackable
///
/// Adding this as a base class for a class, adds GetDeleteTracker() to the interface of the
/// class. This function returns an object which can be checked whether the object has been
/// deleted, and remains valid after the object has been deleted, until all references to the
/// tracker itself have been destroyed.
///
/// This makes it even possible to use the UDeleteTracker inside the deleted class itself, to
/// check the \c this object still exists after making some function call (e.g. callbacks)
/// that might potentially delete it.
///
/// \todo add an active delete tracker, which calls some function when the object is deleted,
/// in a similar way as how boost::trackable works
///
/////////////////////////////////////////////////////////////////////////////////////////////////
class UTrackable
{
protected:
    ///initializes the tracker
    UTrackable()
        :   mDeleteTracker(new UDeleteTracker)
    {}

    ///marks the tracker as deleted
    ~UTrackable()
    {
        mDeleteTracker->mDeleted=true;
    }

public:
    ///get an object that can be used to track whether \c this was deleted
    PDeleteTracker GetDeleteTracker()   {   return mDeleteTracker;  }

private:
    PDeleteTracker mDeleteTracker;
};

/*namespace buola*/ }

#endif
